{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "veterinary-fetish",
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "import importlib\n",
    "import data_logging_functions\n",
    "importlib.reload(data_logging_functions)\n",
    "from data_logging_functions import *\n",
    "import eval_metrics\n",
    "importlib.reload(eval_metrics)\n",
    "from eval_metrics import *\n",
    "import helper_library\n",
    "importlib.reload(helper_library)\n",
    "from helper_library import *\n",
    "import compiler_helper_functions\n",
    "importlib.reload(compiler_helper_functions)\n",
    "from compiler_helper_functions import *\n",
    "import glob\n",
    "## let us now plot relative data\n",
    "from scipy.stats.mstats import gmean\n",
    "from scipy.stats import gstd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "unique-factory",
   "metadata": {},
   "outputs": [],
   "source": [
    "def minimum_and_maximum_positions(a):\n",
    "    if type(a) is list:\n",
    "        minpos = a.index(min(a))\n",
    "        maxpos = a.index(max(a)) \n",
    "    else: #for numpy arrays\n",
    "        minpos = np.where(a == a.min())[0]\n",
    "        maxpos = np.where(a == a.max())[0]\n",
    "    return minpos,maxpos\n",
    "\n",
    "def find_adapt_sequence_ids(num_qubits,max_block_size):\n",
    "    '''\n",
    "    Function to determine the ADAPT sequence IDs for a given block size\n",
    "    '''\n",
    "    if num_qubits%max_block_size == 0:\n",
    "        num_blocks = int(num_qubits/max_block_size)\n",
    "    else:\n",
    "        num_blocks = int(num_qubits/max_block_size)+1\n",
    "    \n",
    "    # qubits per block\n",
    "    qubits_per_block = [max_block_size for _ in range(num_blocks)]\n",
    "    if num_qubits%max_block_size != 0: ## different number of qubits in last block\n",
    "        qubits_per_block[-1] = num_qubits-(max_block_size*(num_blocks-1))\n",
    "    #print('Number of Blocks ', num_blocks)\n",
    "    #print('Qubits per block ', qubits_per_block)\n",
    "    blockwise_qubits = []\n",
    "    \n",
    "    # determine the specifc qubits in each block\n",
    "    for i in range(num_blocks):\n",
    "        _qubits_in_curr_block = []\n",
    "        for qubit in range(qubits_per_block[i]):\n",
    "            curr_qubit = i*max_block_size + qubit\n",
    "            _qubits_in_curr_block.append(curr_qubit)\n",
    "        _qubits_in_curr_block.reverse()\n",
    "        blockwise_qubits.append(_qubits_in_curr_block)\n",
    "    #print('Qubits in each block ',blockwise_qubits)\n",
    "    adapt_sequences_structured, adapt_sequences_unstructured= [],[]\n",
    "    # generate the sequence ids\n",
    "    for block_id in range(num_blocks):\n",
    "        sequences_for_curr_block = []\n",
    "        curr_block_seq_limit = int(math.pow(2,qubits_per_block[block_id]))\n",
    "        #print(curr_block_seq_limit)\n",
    "        for sequence_id in range(curr_block_seq_limit):\n",
    "            dd_seq = ['0' for _ in range(num_qubits)]\n",
    "            #print(dd_seq)\n",
    "            bitstring = get_key_from_decimal(sequence_id,qubits_per_block[block_id])\n",
    "            #print(bitstring)\n",
    "            ## set the required locations \n",
    "            for qubit_id in range(len(blockwise_qubits[block_id])):\n",
    "                #print(blockwise_qubits[block_id][qubit_id],bitstring[qubit_id])\n",
    "                dd_seq[blockwise_qubits[block_id][qubit_id]] = bitstring[qubit_id]\n",
    "            dd_seq.reverse()\n",
    "            dd_seq_key = ''.join([str(elem) for elem in dd_seq])\n",
    "            sequence_id = convert_key_to_decimal(dd_seq_key,num_qubits)\n",
    "            #print('Updated Sequence', dd_seq, ' Sequence ID', sequence_id)\n",
    "            sequences_for_curr_block.append(sequence_id)\n",
    "            adapt_sequences_unstructured.append(sequence_id)\n",
    "        #print(sequences_for_curr_block)\n",
    "        adapt_sequences_structured.append(sequences_for_curr_block)\n",
    "    #print(adapt_sequences_structured)\n",
    "    ## overwrite \n",
    "    #adapt_sequences_structured = [[1,2,4,8]]\n",
    "    return adapt_sequences_structured, adapt_sequences_unstructured\n",
    "\n",
    "def sequence_update(old_sequence,update_sequence):\n",
    "    #print('Pre update Sequence ', old_sequence)\n",
    "    new_sequence = [c for c in old_sequence]\n",
    "    update_sequence = update_sequence[::-1]\n",
    "    for c in range(len(update_sequence)):\n",
    "        if update_sequence[c]=='1':\n",
    "            new_sequence[c] = '1'\n",
    "    #print('Post update Sequence ',old_sequence)\n",
    "    return new_sequence\n",
    "\n",
    "def label_cleanup(given_labels):\n",
    "    '''\n",
    "    Remove the second hyphen from the workload names for a cleaner plot\n",
    "    '''\n",
    "    output_labels = []\n",
    "    for label in given_labels:\n",
    "        counter = label.count('-')\n",
    "        if counter==2:\n",
    "            label = label[::-1]\n",
    "            index = label.find('-')\n",
    "            label = label[:index] +  label[index+1:]\n",
    "            label = label[::-1]\n",
    "        output_labels.append(label)\n",
    "    return output_labels\n",
    "\n",
    "def majority_voted_bitstrings(string_1, string_2):\n",
    "    \n",
    "    majority_voted_string = ['0' for _ in range(len(string_1))]\n",
    "    for i in range(len(string_1)):\n",
    "        if string_1[i] == '1' or string_2[i] == '1':\n",
    "            majority_voted_string[i] = '1'\n",
    "    \n",
    "    majority_voted_string = ''.join([str(elem) for elem in majority_voted_string])    \n",
    "    majority_voted_string_seq = convert_key_to_decimal(majority_voted_string,len(string_1))\n",
    "    \n",
    "    return majority_voted_string , majority_voted_string_seq\n",
    "\n",
    "def extract_final_evaluations_data(final_data,adapt_block_size=None,show_log=0):\n",
    "    \n",
    "    feedback_path = 1 # 0 to turn off, 1 means feedback incorporated\n",
    "    \n",
    "    # gather program name\n",
    "    program = final_data['program_name']\n",
    "    # obtain number of qubits in the program\n",
    "    program_size = len(list(final_data['ideal_counts_baseline'].keys())[0])\n",
    "    \n",
    "    if adapt_block_size is None: # default\n",
    "        adapt_block_size = min(int(program_size/2),3)\n",
    "        if program_size <=6:\n",
    "            adapt_block_size = 3\n",
    "        else:\n",
    "            adapt_block_size = 4\n",
    "    if show_log>0:\n",
    "        print('Program ', program, ' Size ', program_size)\n",
    "    \n",
    "    # ideal output baseline\n",
    "    ideal_output_baseline = final_data['ideal_counts_baseline']\n",
    "    if show_log>1:\n",
    "        print('Ideal Output ', ideal_output_baseline)\n",
    "    # ideal output skeleton circuit\n",
    "    ideal_output_skeleton_circuit = final_data['ideal_counts_skeleton']\n",
    "    if show_log>1:\n",
    "        print('Ideal Output of Skeleton ', ideal_output_skeleton_circuit)\n",
    "    \n",
    "    \n",
    "    \n",
    "    # max DD combinations possible for search \n",
    "    search_space = int(math.pow(2,int(program_size)))\n",
    "    if show_log>0:\n",
    "        print('Total number of DD sequences possible ',search_space)\n",
    "    \n",
    "    \n",
    "    ###################################   NO DD Data    ######################################################\n",
    "    \n",
    "    no_dd_fidelity = fidelity_from_tvd(ideal_output_baseline, final_data['original'][0]['counts'])\n",
    "    if show_log>0:\n",
    "        print('No DD Fidelity ', no_dd_fidelity)\n",
    "        \n",
    "    if show_log>2:\n",
    "        print('No DD Circuit Output ', final_data['original'][0]['counts'])\n",
    "    \n",
    "    ###################################   ADAPT Data   ######################################################\n",
    "    \n",
    "    # Determine the ADAPT Sequence IDs\n",
    "    adapt_sequences, all_adapt_sequences = find_adapt_sequence_ids(program_size,adapt_block_size)\n",
    "    \n",
    "    adapt_predicted_string_xyxy = ['0' for _ in range(program_size)]\n",
    "    adapt_predicted_string_ibmq = ['0' for _ in range(program_size)]\n",
    "    \n",
    "    adapt_second_predicted_string_xyxy = ['0' for _ in range(program_size)]\n",
    "    adapt_second_predicted_string_ibmq = ['0' for _ in range(program_size)]\n",
    "    \n",
    "    \n",
    "    if show_log>1:\n",
    "        print('ADAPT Sequences ', adapt_sequences)\n",
    "    # Shortlist the skeleton circuit outputs for the ADAPT chosen sequences \n",
    "    xyxy_adapt_skeleton_fidelities = np.zeros(len(adapt_sequences))\n",
    "    ibmq_adapt_skeleton_fidelities = np.zeros(len(adapt_sequences))\n",
    "    for adapt_group in range(len(adapt_sequences)):\n",
    "        xyxy_adapt_skeleton_fidelities = np.zeros(len(adapt_sequences[adapt_group]))\n",
    "        ibmq_adapt_skeleton_fidelities = np.zeros(len(adapt_sequences[adapt_group]))\n",
    "        for adapt_dd_seq_id in range(len(adapt_sequences[adapt_group])):\n",
    "            if feedback_path: # keep updating the adapt sequence after finding the best from each group\n",
    "                curr_seq = get_key_from_decimal(adapt_sequences[adapt_group][adapt_dd_seq_id],program_size)\n",
    "                curr_seq_with_feedback = sequence_update(adapt_predicted_string_xyxy,curr_seq)\n",
    "                curr_seq_with_feedback.reverse()\n",
    "                curr_seq_with_feedback_id = convert_key_to_decimal(curr_seq_with_feedback,program_size)\n",
    "                xyxy_skeleton_output_dict = final_data['skeleton'][curr_seq_with_feedback_id]['counts']\n",
    "                ibmq_skeleton_output_dict = final_data['skeleton_ibmq_dd'][curr_seq_with_feedback_id]['counts']\n",
    "                xyxy_adapt_skeleton_fidelities[adapt_dd_seq_id] = fidelity_from_tvd(ideal_output_skeleton_circuit,xyxy_skeleton_output_dict)\n",
    "                ibmq_adapt_skeleton_fidelities[adapt_dd_seq_id] = fidelity_from_tvd(ideal_output_skeleton_circuit,ibmq_skeleton_output_dict)\n",
    "            else:\n",
    "                xyxy_skeleton_output_dict = final_data['skeleton'][adapt_sequences[adapt_group][adapt_dd_seq_id]]['counts']\n",
    "                ibmq_skeleton_output_dict = final_data['skeleton_ibmq_dd'][adapt_sequences[adapt_group][adapt_dd_seq_id]]['counts']\n",
    "                xyxy_adapt_skeleton_fidelities[adapt_dd_seq_id] = fidelity_from_tvd(ideal_output_skeleton_circuit,xyxy_skeleton_output_dict)\n",
    "                ibmq_adapt_skeleton_fidelities[adapt_dd_seq_id] = fidelity_from_tvd(ideal_output_skeleton_circuit,ibmq_skeleton_output_dict)\n",
    "\n",
    "\n",
    "        if show_log>2:\n",
    "            print('Current Group ID', adapt_group , ' Group Sequences ',  adapt_sequences[adapt_group])\n",
    "            print('All Fidelities XYXY ', xyxy_adapt_skeleton_fidelities, ' IBMQ ', ibmq_adapt_skeleton_fidelities)\n",
    "        # Find the optimal sequence ID from the skeletons\n",
    "        _, _xyxy_predicted_seq_id = minimum_and_maximum_positions(xyxy_adapt_skeleton_fidelities)\n",
    "        _, _ibmq_predicted_seq_id = minimum_and_maximum_positions(ibmq_adapt_skeleton_fidelities)\n",
    "        \n",
    "        # second best sequence from current lot\n",
    "        xyxy_adapt_skeleton_fidelities[_xyxy_predicted_seq_id[0]] = -1\n",
    "        ibmq_adapt_skeleton_fidelities[_ibmq_predicted_seq_id[0]] = -1\n",
    "        _, _xyxy_second_predicted_seq_id = minimum_and_maximum_positions(xyxy_adapt_skeleton_fidelities)\n",
    "        _, _ibmq_second_predicted_seq_id = minimum_and_maximum_positions(ibmq_adapt_skeleton_fidelities)\n",
    "        \n",
    "        \n",
    "        if show_log>3:\n",
    "            print('Best Sequence Index in Current Group XYXY ', _xyxy_predicted_seq_id[0], ' IBMQ ',  _ibmq_predicted_seq_id[0])\n",
    "            #print(max(xyxy_adapt_skeleton_fidelities))\n",
    "        curr_best_xyxy_sequence = adapt_sequences[adapt_group][_xyxy_predicted_seq_id[0]]\n",
    "        curr_best_ibmq_sequence = adapt_sequences[adapt_group][_ibmq_predicted_seq_id[0]]\n",
    "        \n",
    "        curr_second_best_xyxy_sequence = adapt_sequences[adapt_group][_xyxy_second_predicted_seq_id[0]]\n",
    "        curr_second_best_ibmq_sequence = adapt_sequences[adapt_group][_ibmq_second_predicted_seq_id[0]]\n",
    "        \n",
    "        \n",
    "        if show_log>3: \n",
    "            print('Best Sequence in Current Group XYXY ', curr_best_xyxy_sequence, ' IBMQ ',  curr_best_ibmq_sequence)\n",
    "            print('Second Best Sequence in Current Group XYXY ', curr_second_best_xyxy_sequence, ' IBMQ ', curr_second_best_ibmq_sequence)\n",
    "        \n",
    "        ## do a global update for the bits\n",
    "        curr_best_xyxy_bitstring = get_key_from_decimal(curr_best_xyxy_sequence,program_size)\n",
    "        curr_best_ibmq_bitstring = get_key_from_decimal(curr_best_ibmq_sequence,program_size)\n",
    "        \n",
    "        ## current second best string \n",
    "        curr_second_best_xyxy_bitstring = get_key_from_decimal(curr_second_best_xyxy_sequence,program_size)\n",
    "        curr_second_best_ibmq_bitstring = get_key_from_decimal(curr_second_best_ibmq_sequence,program_size)\n",
    "        \n",
    "        \n",
    "        if show_log>3:\n",
    "            print('Best Sequence Bitstrings for Current Group XYXY ', curr_best_xyxy_bitstring, ' IBMQ ', curr_best_ibmq_bitstring)\n",
    "            print('Second Best Sequence Bitstrings for Current Group XYXY ', curr_second_best_xyxy_bitstring, ' IBMQ ', curr_second_best_ibmq_bitstring)\n",
    "            \n",
    "\n",
    "        adapt_predicted_string_xyxy = sequence_update(adapt_predicted_string_xyxy,curr_best_xyxy_bitstring)\n",
    "        adapt_predicted_string_ibmq = sequence_update(adapt_predicted_string_ibmq,curr_best_ibmq_bitstring)\n",
    "        \n",
    "        adapt_second_predicted_string_xyxy = sequence_update(adapt_second_predicted_string_xyxy,curr_second_best_xyxy_bitstring)\n",
    "        adapt_second_predicted_string_ibmq = sequence_update(adapt_second_predicted_string_ibmq,curr_second_best_ibmq_bitstring)\n",
    "        \n",
    "        \n",
    "    # Post final update -> reverse the list and then obtain the decimal id\n",
    "    adapt_predicted_string_xyxy.reverse()\n",
    "    adapt_predicted_string_ibmq.reverse()\n",
    "    \n",
    "    adapt_second_predicted_string_xyxy.reverse()\n",
    "    adapt_second_predicted_string_ibmq.reverse()\n",
    "    \n",
    "    xyxy_predicted_seq = ''.join([str(elem) for elem in adapt_predicted_string_xyxy])\n",
    "    ibmq_predicted_seq = ''.join([str(elem) for elem in adapt_predicted_string_ibmq])\n",
    "    xyxy_predicted_seq_id = convert_key_to_decimal(xyxy_predicted_seq,program_size)\n",
    "    ibmq_predicted_seq_id = convert_key_to_decimal(ibmq_predicted_seq,program_size)\n",
    "    \n",
    "    xyxy_second_predicted_seq = ''.join([str(elem) for elem in adapt_second_predicted_string_xyxy])\n",
    "    ibmq_second_predicted_seq = ''.join([str(elem) for elem in adapt_second_predicted_string_ibmq])\n",
    "    \n",
    "    \n",
    "    if show_log>0:\n",
    "        print('First Prediction Sequence from ADAPT XYXY ', xyxy_predicted_seq, 'IBMQ ', ibmq_predicted_seq)\n",
    "        print('Second Prediction Sequence from ADAPT XYXY ', xyxy_second_predicted_seq, 'IBMQ ', ibmq_second_predicted_seq)\n",
    "    \n",
    "    if program_size>5:\n",
    "        xyxy_predicted_seq, xyxy_predicted_seq_id = majority_voted_bitstrings(xyxy_predicted_seq,xyxy_second_predicted_seq)  \n",
    "        ibmq_predicted_seq, ibmq_predicted_seq_id = majority_voted_bitstrings(ibmq_predicted_seq, ibmq_second_predicted_seq)\n",
    "\n",
    "    if show_log>0:\n",
    "        print('Final Prediction Sequence from ADAPT XYXY ', xyxy_predicted_seq, 'IBMQ ', ibmq_predicted_seq)\n",
    "        #print('Second Prediction Sequence from ADAPT XYXY ', xyxy_second_predicted_seq, 'IBMQ ', ibmq_second_predicted_seq)\n",
    "    \n",
    "        \n",
    "    \n",
    "#     xyxy_predicted_seq_id = convert_key_to_decimal(xyxy_predicted_seq,program_size)\n",
    "#     xyxy_second_predicted_seq_id = convert_key_to_decimal(xyxy_second_predicted_seq,program_size)\n",
    "    \n",
    "#     ibmq_predicted_seq_id = convert_key_to_decimal(ibmq_predicted_seq,program_size)\n",
    "#     ibmq_second_predicted_seq_id = convert_key_to_decimal(ibmq_second_predicted_seq,program_size)\n",
    "# #     if xyxy_predicted_seq_id ==0:\n",
    "#         # override \n",
    "#         xyxy_predicted_seq_id = xyxy_second_predicted_seq_id\n",
    "#         xyxy_predicted_seq = xyxy_second_predicted_seq\n",
    "        \n",
    "#     if ibmq_predicted_seq_id ==0:\n",
    "#         ## override \n",
    "#         ibmq_predicted_seq_id = ibmq_second_predicted_seq_id\n",
    "#         ibmq_predicted_seq = ibmq_second_predicted_seq\n",
    "        \n",
    "    \n",
    "    if show_log>0:\n",
    "        print('ADAPT Block Size ' , adapt_block_size)\n",
    "        print('Number of ADAPT Sequences ', len(all_adapt_sequences))\n",
    "        print('ADAPT Predicted Sequence XYXY ', xyxy_predicted_seq_id, ': ', xyxy_predicted_seq, ' IBMQ ', ibmq_predicted_seq_id, ': ', ibmq_predicted_seq)\n",
    "    \n",
    "    \n",
    "    # what is the optimal fidelity from ADAPT of the real circuit ?\n",
    "    xyxy_true_circuit_dict = final_data['original'][xyxy_predicted_seq_id]['counts']\n",
    "    ibmq_true_circuit_dict = final_data['original_ibmq_dd'][ibmq_predicted_seq_id]['counts']\n",
    "    \n",
    "    xyxy_adapt_fidelity = fidelity_from_tvd(ideal_output_baseline, xyxy_true_circuit_dict)\n",
    "    ibmq_adapt_fidelity = fidelity_from_tvd(ideal_output_baseline, ibmq_true_circuit_dict)\n",
    "    \n",
    "    if show_log>0:\n",
    "        print('ADAPT Predicted Sequence Fidelity XYXY ', xyxy_adapt_fidelity, ' IBMQ ', ibmq_adapt_fidelity)\n",
    "    if show_log>2:\n",
    "        print('ADAPT Output Histogram XYXY ', xyxy_true_circuit_dict)\n",
    "        print('ADAPT Output Histogram IBMQ ', ibmq_true_circuit_dict)\n",
    "    \n",
    "    ###################################   Exhaustive   ######################################################\n",
    "    \n",
    "    xyxy_skeleton_all_fidelities = np.zeros(search_space)\n",
    "    ibmq_skeleton_all_fidelities = np.zeros(search_space)\n",
    "    for skeleton_seq_id in range(search_space):\n",
    "        xyxy_counts = final_data['skeleton'][skeleton_seq_id]['counts']\n",
    "        ibmq_counts = final_data['skeleton_ibmq_dd'][skeleton_seq_id]['counts']\n",
    "        \n",
    "        xyxy_skeleton_all_fidelities[skeleton_seq_id] = fidelity_from_tvd(ideal_output_skeleton_circuit, xyxy_counts)\n",
    "        ibmq_skeleton_all_fidelities[skeleton_seq_id] = fidelity_from_tvd(ideal_output_skeleton_circuit, ibmq_counts)\n",
    "        \n",
    "    # Find the optimal sequence ID from all the skeletons\n",
    "    _, _xyxy_exhaustive_search_seq_id = minimum_and_maximum_positions(xyxy_skeleton_all_fidelities)\n",
    "    _, _ibmq_exhaustive_search_seq_id = minimum_and_maximum_positions(ibmq_skeleton_all_fidelities)\n",
    "    xyxy_exhaustive_search_seq_id = _xyxy_exhaustive_search_seq_id[0]\n",
    "    ibmq_exhaustive_search_seq_id = _ibmq_exhaustive_search_seq_id[0]\n",
    "    \n",
    "    xyxy_true_circuit_dict = final_data['original'][xyxy_exhaustive_search_seq_id]['counts']\n",
    "    ibmq_true_circuit_dict = final_data['original_ibmq_dd'][ibmq_exhaustive_search_seq_id]['counts']\n",
    "    xyxy_exhaustive_search_seq = get_key_from_decimal(xyxy_exhaustive_search_seq_id,program_size)\n",
    "    ibmq_exhaustive_search_seq = get_key_from_decimal(ibmq_exhaustive_search_seq_id,program_size)\n",
    "    \n",
    "    xyxy_exhaustive_search_fidelity = fidelity_from_tvd(ideal_output_baseline, xyxy_true_circuit_dict)\n",
    "    ibmq_exhaustive_search_fidelity = fidelity_from_tvd(ideal_output_baseline, ibmq_true_circuit_dict)\n",
    "    \n",
    "    if show_log>0:\n",
    "        print('Exhaustive Decoy Search Sequence Id XYXY ', xyxy_exhaustive_search_seq_id, ': ',xyxy_exhaustive_search_seq, ' IBMQ ', ibmq_exhaustive_search_seq_id, ': ', ibmq_exhaustive_search_seq)\n",
    "        print('Exhaustive Decoy Search Fidelity XYXY ', xyxy_exhaustive_search_fidelity, ' IBMQ ', ibmq_exhaustive_search_fidelity)\n",
    "        \n",
    "    ###################################   All-DD Data  ######################################################\n",
    "    \n",
    "    xyxy_all_dd_circuit_dict = final_data['original'][search_space-1]['counts'] # last sequence \n",
    "    ibmq_all_dd_circuit_dict = final_data['original_ibmq_dd'][search_space-1]['counts']\n",
    "    xyxy_all_dd_fidelity = fidelity_from_tvd(ideal_output_baseline, xyxy_all_dd_circuit_dict)\n",
    "    ibmq_all_dd_fidelity = fidelity_from_tvd(ideal_output_baseline, ibmq_all_dd_circuit_dict)\n",
    "    \n",
    "    if show_log>0:\n",
    "        print('All-DD Fidelity XYXY ', xyxy_all_dd_fidelity, ' IBMQ ', ibmq_all_dd_fidelity)\n",
    "    if show_log>2:\n",
    "        print('All DD Output XYXY ', xyxy_all_dd_circuit_dict)\n",
    "        print('All DD Output IBMQ ', ibmq_all_dd_circuit_dict)\n",
    "        print('Gate Cost Baseline : ', final_data['original'][0]['gate_cost'], ' All-DD XYXY ', final_data['original'][search_space-1]['gate_cost'], ' All-DD IBMQ ', final_data['original_ibmq_dd'][search_space-1]['gate_cost'])\n",
    "    ###################################  Runtime Best  ######################################################\n",
    "    \n",
    "    xyxy_exhaustive_fidelities = np.zeros(search_space)\n",
    "    ibmq_exhaustive_fidelities = np.zeros(search_space)\n",
    "    for sequence_id in range(search_space):\n",
    "        xyxy_counts = final_data['original'][sequence_id]['counts']\n",
    "        ibmq_counts = final_data['original_ibmq_dd'][sequence_id]['counts']\n",
    "        \n",
    "        xyxy_exhaustive_fidelities[sequence_id] = fidelity_from_tvd(ideal_output_baseline, xyxy_counts)\n",
    "        ibmq_exhaustive_fidelities[sequence_id] = fidelity_from_tvd(ideal_output_baseline, ibmq_counts)\n",
    "        \n",
    "    ## find the sequence id of the run time best\n",
    "    _, _xyxy_runtime_best_seq_id = minimum_and_maximum_positions(xyxy_exhaustive_fidelities)\n",
    "    _, _ibmq_runtime_best_seq_id = minimum_and_maximum_positions(ibmq_exhaustive_fidelities)\n",
    "    \n",
    "    xyxy_runtime_best_fidelity = max(xyxy_exhaustive_fidelities)\n",
    "    ibmq_runtime_best_fidelity = max(ibmq_exhaustive_fidelities)\n",
    "    \n",
    "    xyxy_runtime_best_seq_id = get_key_from_decimal(_xyxy_runtime_best_seq_id[0],program_size)\n",
    "    ibmq_runtime_best_seq_id = get_key_from_decimal(_ibmq_runtime_best_seq_id[0],program_size)\n",
    "    \n",
    "    \n",
    "    if show_log>0:\n",
    "        print('Runtime Best Sequence XYXY ' , _xyxy_runtime_best_seq_id[0], ': ', xyxy_runtime_best_seq_id, ' IBMQ ', _ibmq_runtime_best_seq_id[0], ': ', ibmq_runtime_best_seq_id)\n",
    "        print('Runtime Best Fidelity XYXY ' , xyxy_runtime_best_fidelity , ' IBMQ ', ibmq_runtime_best_fidelity)\n",
    "    \n",
    "    xyxy_fidelities = [no_dd_fidelity, xyxy_all_dd_fidelity, xyxy_adapt_fidelity, xyxy_exhaustive_search_fidelity, xyxy_runtime_best_fidelity]\n",
    "    ibmq_fidelities = [no_dd_fidelity, ibmq_all_dd_fidelity, ibmq_adapt_fidelity, ibmq_exhaustive_search_fidelity, ibmq_runtime_best_fidelity]\n",
    "    \n",
    "    xyxy_sequences = [0, search_space-1, xyxy_predicted_seq_id, xyxy_exhaustive_search_seq_id, xyxy_runtime_best_seq_id]\n",
    "    ibmq_sequences = [0, search_space-1, ibmq_predicted_seq_id, ibmq_exhaustive_search_seq_id, ibmq_runtime_best_fidelity]\n",
    "    \n",
    "    # all DD, adapt , exhaustive, runtime \n",
    "   \n",
    "    relative_fidelities_xyxy = np.array([xyxy_all_dd_fidelity,xyxy_adapt_fidelity,xyxy_exhaustive_search_fidelity,xyxy_runtime_best_fidelity])/no_dd_fidelity\n",
    "    relative_fidelities_ibmq = np.array([ibmq_all_dd_fidelity,ibmq_adapt_fidelity,ibmq_exhaustive_search_fidelity,ibmq_runtime_best_fidelity])/no_dd_fidelity\n",
    "    \n",
    "    relative_xyxy_performance_adapt = np.zeros(2)\n",
    "    relative_xyxy_performance_adapt[0] = xyxy_adapt_fidelity/no_dd_fidelity\n",
    "    relative_xyxy_performance_adapt[1] = xyxy_adapt_fidelity/xyxy_all_dd_fidelity\n",
    "    \n",
    "    relative_ibmq_performance_adapt = np.zeros(2) # numbers for IBMQ sequence\n",
    "    relative_ibmq_performance_adapt[0] = ibmq_adapt_fidelity/no_dd_fidelity\n",
    "    relative_ibmq_performance_adapt[1] = ibmq_adapt_fidelity/ibmq_all_dd_fidelity\n",
    "    \n",
    "    \n",
    "    #print('Relative Numbers ', relative_fidelities_xyxy, relative_fidelities_ibmq)\n",
    "    \n",
    "    report = {'program': program, 'size': program_size, \n",
    "              'xyxy_fidelities': xyxy_fidelities, 'ibmq_fidelities': ibmq_fidelities, \n",
    "              'rel_xyxy_fidelities': relative_fidelities_xyxy, 'rel_ibmq_fidelities': relative_fidelities_ibmq, \n",
    "              'num_decoy_circuits': len(adapt_sequences), 'total_decoy_circuits': search_space,\n",
    "              'xyxy_sequences': xyxy_sequences, 'ibmq_sequences': ibmq_sequences,\n",
    "              'relative_xyxy_performance_adapt': relative_xyxy_performance_adapt,\n",
    "              'relative_ibmq_performance_adapt':relative_ibmq_performance_adapt}\n",
    "    \n",
    "    return report\n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "incorporated-minister",
   "metadata": {},
   "outputs": [],
   "source": [
    "ibmq_names = {'ibmq_guadalupe': 'IBMQ-Guadalupe', 'ibmq_manhattan': 'IBMQ-Manhattan',\n",
    "                  'ibmq_rome': 'IBMQ-Rome','ibmq_bogota': 'IBMQ-Bogota','ibmq_belem':'IBMQ-Belem','ibmq_quito':'IBMQ-Quito',\n",
    "                  'ibmq_paris': 'IBMQ-Paris', 'ibmq_toronto': 'IBMQ-Toronto', 'ibmq_casablanca': 'IBMQ-Casablanca'}\n",
    "'''\n",
    "Wrapper script to obtain all the required data\n",
    "'''\n",
    "def final_evaluation_data_generation_wrapper(machine):\n",
    "    ## compare the results from each machine\n",
    "    ibmq_names = {'ibmq_guadalupe': 'IBMQ-Guadalupe', 'ibmq_manhattan': 'IBMQ-Manhattan',\n",
    "                  'ibmq_rome': 'IBMQ-Rome','ibmq_bogota': 'IBMQ-Bogota','ibmq_belem':'IBMQ-Belem','ibmq_quito':'IBMQ-Quito',\n",
    "                  'ibmq_paris': 'IBMQ-Paris', 'ibmq_toronto': 'IBMQ-Toronto', 'ibmq_casablanca': 'IBMQ-Casablanca'}\n",
    "    #machine = 'ibmq_rome'\n",
    "    num_bars = 4\n",
    "    files = '../logfiles/' + machine+'*.log'\n",
    "    filelist =  sorted(glob.glob(files))\n",
    "    print('Number of programs evaluated for ', machine, ' :', len(filelist))\n",
    "    ## collect data for plotting\n",
    "\n",
    "    relative_xyxy_fidelity_data = np.zeros((num_bars,len(filelist)+1))\n",
    "    relative_ibmq_fidelity_data = np.zeros((num_bars,len(filelist)+1)) # one extra entry for GMEAN\n",
    "    \n",
    "    #adapt to 0: No-DD and 1: All-DD\n",
    "    relative_xyxy_results_for_adapt =np.zeros((2,len(filelist)+1))\n",
    "    relative_ibmq_results_for_adapt =np.zeros((2,len(filelist)+1))\n",
    "    \n",
    "    ## sort logfiles in the order of increasing size\n",
    "    sizes = np.zeros(len(filelist))\n",
    "    for logfile_id in range(len(filelist)):\n",
    "        logname = filelist[logfile_id]\n",
    "        read_data = read_data_dictionary_from_logfile(logname)\n",
    "        sizes[logfile_id] = len(list(read_data['ideal_counts_baseline'].keys())[0])\n",
    "    \n",
    "    sorted_indices = np.argsort(sizes, axis=0)\n",
    "    \n",
    "    sorted_filelist = []\n",
    "    for index in range(len(sorted_indices)):\n",
    "        sorted_filelist.append(filelist[sorted_indices[index]])\n",
    "    \n",
    "    \n",
    "    workload_labels = []\n",
    "    for logfile_id in range(len(sorted_filelist)):\n",
    "        logname = sorted_filelist[logfile_id]\n",
    "        print(logname)\n",
    "        read_data = read_data_dictionary_from_logfile(logname)\n",
    "        evaluated_data = extract_final_evaluations_data(read_data)\n",
    "        workload_labels.append(evaluated_data['program']+'\\n'+str(round(evaluated_data['xyxy_fidelities'][0],2)))\n",
    "        for i in range(num_bars):\n",
    "            relative_xyxy_fidelity_data[i][logfile_id] = evaluated_data['rel_xyxy_fidelities'][i]\n",
    "            relative_ibmq_fidelity_data[i][logfile_id] = evaluated_data['rel_ibmq_fidelities'][i]\n",
    "        relative_xyxy_results_for_adapt[0][logfile_id] = evaluated_data['relative_xyxy_performance_adapt'][0]\n",
    "        relative_xyxy_results_for_adapt[1][logfile_id] = evaluated_data['relative_xyxy_performance_adapt'][1]\n",
    "        relative_ibmq_results_for_adapt[0][logfile_id] = evaluated_data['relative_ibmq_performance_adapt'][0]\n",
    "        relative_ibmq_results_for_adapt[1][logfile_id] = evaluated_data['relative_ibmq_performance_adapt'][1]\n",
    "        \n",
    "        \n",
    "    '''\n",
    "    Add Gmean data for plotting\n",
    "    ''' \n",
    "    workload_labels.append('GMean')\n",
    "    workload_labels = label_cleanup(workload_labels)\n",
    "    \n",
    "    \n",
    "    ## add the Baseline Fidelity at the label bottom\n",
    "    \n",
    "    \n",
    "    \n",
    "    \n",
    "    for i in range(num_bars):\n",
    "        relative_xyxy_fidelity_data[i][-1] = gmean(relative_xyxy_fidelity_data[i][0:len(filelist)-1])\n",
    "        relative_ibmq_fidelity_data[i][-1] = gmean(relative_ibmq_fidelity_data[i][0:len(filelist)-1])\n",
    "        if i <2:\n",
    "            relative_xyxy_results_for_adapt[i][-1] = gmean(relative_xyxy_results_for_adapt[i][0:len(filelist)-1])\n",
    "            relative_ibmq_results_for_adapt[i][-1] = gmean(relative_ibmq_results_for_adapt[i][0:len(filelist)-1])\n",
    "    \n",
    "    ## statistics \n",
    "    print('-------------- XYXY Statistics -----------')\n",
    "    print('GMean All DD: ', round(relative_xyxy_fidelity_data[0][-1],2), ' ADAPT ', round(relative_xyxy_fidelity_data[1][-1],2) , ' Runtime Best', round(relative_xyxy_fidelity_data[3][-1],2))\n",
    "    print('Min improvement All DD ', round(min(relative_xyxy_fidelity_data[0]),2), ' ADAPT ', round(min(relative_xyxy_fidelity_data[1]),2), ' Runtime Best ', round(min(relative_xyxy_fidelity_data[3]),2))\n",
    "    print('Max improvement All DD ', round(max(relative_xyxy_fidelity_data[0]),2), ' ADAPT ', round(max(relative_xyxy_fidelity_data[1]),2), ' Runtime Best ', round(max(relative_xyxy_fidelity_data[3]),2))\n",
    "    \n",
    "    \n",
    "    print('-------------- IBMQ-DD Statistics -----------')\n",
    "    print('GMean All DD: ', round(relative_ibmq_fidelity_data[0][-1],2), ' ADAPT ', round(relative_ibmq_fidelity_data[1][-1],2) , ' Runtime Best', round(relative_ibmq_fidelity_data[3][-1],2))\n",
    "    print('Min improvement All DD ', round(min(relative_ibmq_fidelity_data[0]),2), ' ADAPT ', round(min(relative_ibmq_fidelity_data[1]),2), ' Runtime Best ', round(min(relative_ibmq_fidelity_data[3]),2))\n",
    "    print('Max improvement All DD ', round(max(relative_ibmq_fidelity_data[0]),2), ' ADAPT ', round(max(relative_ibmq_fidelity_data[1]),2), ' Runtime Best ', round(max(relative_ibmq_fidelity_data[3]),2))\n",
    "    \n",
    "    \n",
    "    \n",
    "    print('----------- Relative Statistics ----------')\n",
    "    print('XYXY: ADAPT to No-DD : Gmean : ', round(relative_xyxy_results_for_adapt[0][-1],2), ' Max: ', round(max(relative_xyxy_results_for_adapt[0]),2))\n",
    "    print('XYXY: ADAPT to All-DD : Gmean : ', round(relative_xyxy_results_for_adapt[1][-1],2), ' Max: ', round(max(relative_xyxy_results_for_adapt[1]),2))\n",
    "    print('IBMQ-DD: ADAPT to No-DD : Gmean : ', round(relative_ibmq_results_for_adapt[0][-1],2), ' Max: ', round(max(relative_ibmq_results_for_adapt[0]),2))\n",
    "    print('IBMQ-DD: ADAPT to All-DD : Gmean : ', round(relative_ibmq_results_for_adapt[1][-1],2), ' Max: ', round(max(relative_ibmq_results_for_adapt[1]),2))\n",
    "    \n",
    "    \n",
    "    \n",
    "    return relative_xyxy_fidelity_data, relative_ibmq_fidelity_data, workload_labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "adjacent-connecticut",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of programs evaluated for  ibmq_guadalupe  : 3\n",
      "../logfiles/ibmq_guadalupe_QFT-7-B_4_9_17.log\n",
      "../logfiles/ibmq_guadalupe_QFT-7-C_4_11_12.log\n",
      "../logfiles/ibmq_guadalupe_QAOA-10_4_6_20.log\n",
      "-------------- XYXY Statistics -----------\n",
      "GMean All DD:  1.25  ADAPT  1.31  Runtime Best 1.66\n",
      "Min improvement All DD  0.67  ADAPT  1.1  Runtime Best  1.34\n",
      "Max improvement All DD  1.57  ADAPT  3.1  Runtime Best  3.1\n",
      "-------------- IBMQ-DD Statistics -----------\n",
      "GMean All DD:  1.06  ADAPT  1.23  Runtime Best 1.57\n",
      "Min improvement All DD  0.4  ADAPT  0.92  Runtime Best  1.27\n",
      "Max improvement All DD  1.21  ADAPT  1.33  Runtime Best  2.16\n",
      "----------- Relative Statistics ----------\n",
      "XYXY: ADAPT to No-DD : Gmean :  1.31  Max:  3.1\n",
      "XYXY: ADAPT to All-DD : Gmean :  1.05  Max:  4.65\n",
      "IBMQ-DD: ADAPT to No-DD : Gmean :  1.23  Max:  1.33\n",
      "IBMQ-DD: ADAPT to All-DD : Gmean :  1.17  Max:  2.31\n"
     ]
    }
   ],
   "source": [
    "machine = 'ibmq_guadalupe'\n",
    "relative_xyxy_fidelity_data, relative_ibmq_fidelity_data, workload_labels = final_evaluation_data_generation_wrapper(machine)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "gorgeous-detail",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of programs evaluated for  ibmq_toronto  : 4\n",
      "../logfiles/ibmq_toronto_QPEA-5_4_7_12.log\n",
      "../logfiles/ibmq_toronto_BV-7_4_8_10.log\n",
      "../logfiles/ibmq_toronto_QFT-6-B_4_7_10.log\n",
      "../logfiles/ibmq_toronto_BV-8_4_8_9.log\n",
      "-------------- XYXY Statistics -----------\n",
      "GMean All DD:  1.48  ADAPT  1.5  Runtime Best 2.31\n",
      "Min improvement All DD  0.94  ADAPT  0.77  Runtime Best  1.06\n",
      "Max improvement All DD  2.61  ADAPT  3.06  Runtime Best  6.6\n",
      "-------------- IBMQ-DD Statistics -----------\n",
      "GMean All DD:  1.39  ADAPT  1.6  Runtime Best 1.79\n",
      "Min improvement All DD  1.01  ADAPT  1.23  Runtime Best  1.23\n",
      "Max improvement All DD  2.29  ADAPT  2.67  Runtime Best  3.33\n",
      "----------- Relative Statistics ----------\n",
      "XYXY: ADAPT to No-DD : Gmean :  1.5  Max:  3.06\n",
      "XYXY: ADAPT to All-DD : Gmean :  1.02  Max:  1.89\n",
      "IBMQ-DD: ADAPT to No-DD : Gmean :  1.6  Max:  2.67\n",
      "IBMQ-DD: ADAPT to All-DD : Gmean :  1.15  Max:  1.22\n"
     ]
    }
   ],
   "source": [
    "machine = 'ibmq_toronto'\n",
    "relative_xyxy_fidelity_data, relative_ibmq_fidelity_data, workload_labels = final_evaluation_data_generation_wrapper(machine)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "promotional-violation",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
